package nl.boelen.game.level;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;

import nl.boelen.game.client.Client;
import nl.boelen.game.entities.Entity;
import nl.boelen.game.entities.Player;
import nl.boelen.game.entities.PlayerMP;
import nl.boelen.game.gfx.Colors;
import nl.boelen.game.gfx.Screen;
import nl.boelen.game.level.tile.Tile;

public class Level {
    // private Map map = null;
    private byte[] tiles;
    private int levelTick = 0;
    public int width;
    public int height;
    private static final List<Entity> entities = new ArrayList<Entity>();
    private String imagePath;
    private BufferedImage image;
    private Client client;

    public Level(Client client, String imagePath) {
        this.client = client;
        if (imagePath != null) {
            this.imagePath = imagePath;
            this.loadLevelFromFile();
        } else {
            this.width = 64;
            this.height = 64;
            tiles = new byte[width * height];
            this.generateLevel();
        }
    }

    public Level(Client client) {
        this.client = client;
        // this.map = new Map("savegame", client);

        // ///////////////////////
        this.width = 32;
        this.height = 32;
        tiles = new byte[width * height];
        this.generateLevel();
        // ///////////////////////
    }

    private synchronized List<Entity> getEntities() {
        return entities;
    }

    private void loadLevelFromFile() {
        try {
            this.image = ImageIO.read(Level.class.getResource(this.imagePath));
            this.width = image.getWidth();
            this.height = image.getHeight();
            tiles = new byte[width * height];
            this.loadTiles();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void loadTiles() {
        int[] tileColors = this.image.getRGB(0, 0, width, height, null, 0, width);
        Random r = new Random();
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                tileLoop: for (Tile t : Tile.tiles) {
                    if (t != null && t.getIndexColor() == tileColors[x + y * width]) {
                        if (t.getId() == Tile.GRASSID) {
                            int num = r.nextInt(200);
                            if (num < 120) {
                                tiles[x + y * width] = Tile.GRASS1.getId();
                            } else if (num >= 120 && num < 194) {
                                tiles[x + y * width] = Tile.GRASS2.getId();
                            } else if (num >= 194 && num < 196) {
                                tiles[x + y * width] = Tile.GRASS3.getId();
                            } else if (num >= 196 && num < 198) {
                                tiles[x + y * width] = Tile.GRASS4.getId();
                            } else {
                                tiles[x + y * width] = Tile.GRASS5.getId();
                            }
                        } else {
                            this.tiles[x + y * width] = t.getId();
                        }
                        break tileLoop;
                    }
                }
            }
        }
    }

    public void generateLevel() {
        Random r = new Random();
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (r.nextInt(5) < 2) {
                    tiles[x + y * width] = Tile.GRASS1.getId();
                } else {
                    tiles[x + y * width] = Tile.GRASS2.getId();
                }
            }
        }
    }

    public void tick() {
        levelTick++;
        for (Entity e : getEntities()) {
            if (e != null) {
                if (e instanceof Player) {
                    Player p = (Player) e;
                    p.tick();
                } else {
                    e.tick();
                }
            }
        }

        for (Tile t : Tile.tiles) {
            if (t == null) {
                break;
            }
            t.tick();
        }
    }

    public void renderTiles(Screen screen, int xOffset, int yOffset) {
        if (xOffset < 0) {
            xOffset = 0;
        }
        if (xOffset > (width << 3) - screen.width) {
            xOffset = (width << 3) - screen.width;
        }
        if (yOffset < 0) {
            yOffset = 0;
        }
        if (yOffset > (height << 3) - screen.height) {
            yOffset = (height << 3) - screen.height;
        }

        screen.setOffset(xOffset, yOffset);

        for (int y = (yOffset >> 3); y <= (yOffset + screen.height >> 3); y++) {
            for (int x = (xOffset >> 3); x <= (xOffset + screen.width >> 3); x++) {
                Tile t = getTile(x, y);
                screen.render((x << 3), (y << 3), t.getTileId(), t.getTileColor(), t.getTileMirrorBit(), 1, true);
            }
        }
    }

    public void renderEntities(Screen screen, Player player) {
        Entity c = null;
        client.playerHovered = null;
        for (Entity e : getEntities()) {
            // Always draw yourself last (on top of all other players)
            if (e == player) {
                c = e;
            } else {
                e.render(screen);
            }
        }
        if (c != null) {
            c.render(screen);
        }
    }

    public void renderConnection(Screen screen) {
        screen.render(screen.xOffset + screen.width - 9, screen.yOffset + 1, 1 + 23 * 32, Colors.get(-1, 000, 555, -1), 0, 1);
        if (!client.serverOnline) {
            if (levelTick % 180 < 120) {
                screen.render(screen.xOffset + screen.width - 9, screen.yOffset + 1, 0 + 23 * 32, Colors.get(-1, 500, -1, -1), 0, 1);
            }
        }
    }

    public Tile getTile(int x, int y) {
        if (x < 0 || y < 0 || x >= width || y >= height) {
            return Tile.VOID;
        }
        return Tile.tiles[tiles[x + y * width]];
    }

    public void addEntity(Entity entity) {
        getEntities().add(entity);
    }

    public PlayerMP getPlayerMP(final String uniqueKey) {
        for (Entity e : getEntities()) {
            if (e instanceof PlayerMP && ((PlayerMP) e).getUniqueKey().equals(uniqueKey)) {
                return (PlayerMP) e;
            }
        }
        return null;
    }

    public boolean doesPlayerMPExists(final String uniqueKey) {
        for (Entity e : getEntities()) {
            if (e instanceof PlayerMP && ((PlayerMP) e).getUniqueKey().equals(uniqueKey)) {
                return true;
            }
        }
        return false;
    }

    public void removePlayerMP(final String uniqueKey) {
        int index = 0;
        boolean found = false;
        for (Entity e : getEntities()) {
            if (e instanceof PlayerMP && ((PlayerMP) e).getUniqueKey().equals(uniqueKey)) {
                found = true;
                break;
            }
            index++;
        }

        if (found && index <= getEntities().size()) {
            getEntities().remove(index);
        }
    }

    /**
     * Remove all the other players from the entities
     * 
     * @param player
     *            The client
     */
    public void closedServer(final Player player) {
        int index = 0;
        for (Entity e : getEntities()) {
            index++;
            if (e instanceof PlayerMP && !((PlayerMP) e).getUniqueKey().equals(player.getUniqueKey())) {
                getEntities().remove(index);
            }
        }
    }
}
